package com.jprocms.module.cms.controller.portal.page;

import com.jpro.framework.common.enums.UserTypeEnum;
import com.jpro.framework.common.exception.ServiceException;
import com.jpro.framework.security.core.LoginUser;
import com.jpro.framework.security.core.util.SecurityFrameworkUtils;
import com.jprocms.module.cms.controller.admin.content.vo.ContentFileVo;
import com.jprocms.module.cms.dal.dataobject.content.ContentCountDO;
import com.jprocms.module.cms.dal.dataobject.content.ContentDO;
import com.jprocms.module.cms.dal.dataobject.site.SiteDO;
import com.jprocms.module.cms.enums.EnumContentStatus;
import com.jprocms.module.cms.service.content.ContentCountService;
import com.jprocms.module.cms.service.content.ContentService;
import com.jprocms.module.cms.service.site.SiteService;
import com.jprocms.module.cms.util.CommonParamValidUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotNull;
import java.io.IOException;
import java.util.List;
import java.util.Map;

import static com.jpro.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.jprocms.module.cms.constant.CmsSysConstants.*;
import static com.jprocms.module.cms.enums.ErrorCodeConstants.*;
import static com.jprocms.module.cms.util.FrontContextUtil.PAGE;
import static com.jprocms.module.cms.util.FrontContextUtil.PAGE_URL_RESOLVER;


/**
 * 前台文章 Controller
 *
 * @author jprocms
 */
@Slf4j
@Controller("contentFrontController")
public class ContentController {

    public static final String TPL_NOAUTH = "sys/no_auth";

    @GetMapping({CONTENT_PREFIX + "/{id:[0-9]+}", CONTENT_PREFIX + "/{id:[0-9]+}/{page:[\\d]+}",
            "/{sitePath:[\\w-]+}" + CONTENT_PREFIX + "/{id:[0-9]+}"
            , "/{sitePath:[\\w-]+}" + CONTENT_PREFIX + "/{id:[0-9]+}_{page:[\\d]+}",
            "/{customContentPrefix:[\\w-]+}" + "/{id:[0-9]+}"
            , "/{customContentPrefix:[\\w-]+}" + "/{id:[0-9]+}_{page:[\\d]+}",
            "/{sitePath:[\\w-]+}" + "/{customContentPrefix:[\\w-]+}" + "/{id:[0-9]+}"
            , "/{sitePath:[\\w-]+}" + "/{customContentPrefix:[\\w-]+}" + "/{id:[0-9]+}_{page:[\\d]+}",
    })
    public String content(@PathVariable Long id, @PathVariable(required = false) String sitePath, @PathVariable(required = false) Integer page,
                          @RequestParam(required = false) Boolean preview, HttpServletRequest request, Map<String, Object> modelMap) {
        SiteDO site = siteService.getSite(sitePath);
        LoginUser user = SecurityFrameworkUtils.getLoginUser();
        ContentDO contentDO = new ContentDO();
        try {
            contentDO = validateContent(id, site, user, preview);
        } catch (ServiceException e) {
            //无权限则定位到模板页面没有权限的
            if (e.getCode().equals(NO_AUTHORITY.getCode())) {
                return site.joinTemplate(TPL_NOAUTH);
            } else if (e.getCode().equals(CONTENT_NOT_EXISTS.getCode())) {
                return site.joinTemplate(TPL_PAGE_NOT_NOUNT);
            }
        }
        modelMap.put("content", contentDO);
        modelMap.put("channel", contentDO.getChannel());
        modelMap.put(PAGE, CommonParamValidUtil.validPage(page));
        modelMap.put(PAGE_URL_RESOLVER, contentDO);
        return contentDO.getTpl();
    }

    @GetMapping({CONTENT_PREFIX + "/{id:[0-9]+}/live-preview", CONTENT_PREFIX + "/{id:[0-9]+}/{page:[\\d]+}/live-preview",
            "/{sitePath:[\\w-]+}" + CONTENT_PREFIX + "/{id:[0-9]+}/live-preview"
            , "/{sitePath:[\\w-]+}" + CONTENT_PREFIX + "/{id:[0-9]+}_{page:[\\d]+}/live-preview",
            "/{customContentPrefix:[\\w-]+}" + "/{id:[0-9]+}/live-preview"
            , "/{customContentPrefix:[\\w-]+}" + "/{id:[0-9]+}_{page:[\\d]+}/live-preview",
            "/{sitePath:[\\w-]+}" + "/{customContentPrefix:[\\w-]+}" + "/{id:[0-9]+}/live-preview"
            , "/{sitePath:[\\w-]+}" + "/{customContentPrefix:[\\w-]+}" + "/{id:[0-9]+}_{page:[\\d]+}/live-preview",
    })
    public String livePreviewContent(@PathVariable Long id, @PathVariable(required = false) String sitePath, @PathVariable(required = false) Integer page,
                                     HttpServletRequest request, Map<String, Object> modelMap) {
        SiteDO site = siteService.getSite(sitePath);
        LoginUser user = SecurityFrameworkUtils.getLoginUser();
        ContentDO contentDO = new ContentDO();
        try {
            contentDO = validateLivePreviewContent(id, site, user, true);
        } catch (ServiceException e) {
            //无权限则定位到模板页面没有权限的
            if (e.getCode().equals(NO_AUTHORITY.getCode())) {
                return site.joinTemplate(TPL_NOAUTH);
            } else if (e.getCode().equals(CONTENT_NOT_EXISTS.getCode())) {
                return site.joinTemplate(TPL_PAGE_NOT_NOUNT);
            }
        }
        modelMap.put("content", contentDO);
        modelMap.put("channel", contentDO.getChannel());
        modelMap.put(PAGE, CommonParamValidUtil.validPage(page));
        modelMap.put(PAGE_URL_RESOLVER, contentDO);
        return contentDO.getTpl();
    }

    @GetMapping({"/download/{id:[\\d]+}", "/download/{id:[\\d]+}/{index:[\\d]+}",
            "/{sitePath:[\\w-]+}/download/{id:[\\d]+}", "/{sitePath:[\\w-]+}/download/{id:[\\d]+}/{index:[\\d]+}"})
    public void download(@PathVariable Long id, @PathVariable(required = false) Integer index,
                         @PathVariable(required = false) String sitePath,
                         @RequestParam long time, @NotNull String key,
                         HttpServletRequest request, HttpServletResponse response) throws IOException {
        SiteDO site = siteService.getSite(sitePath);
        LoginUser user = SecurityFrameworkUtils.getLoginUser();
        ContentDO contentDO = validateContent(id, site, user, null);
        String fileUrl, fileName;
        if (index != null) {
            List<ContentFileVo> attachs = contentDO.getAttachs();
            if (index >= attachs.size()) {
                log.error("Content file not found. id=" + id + ", index=" + index);
                throw exception(CONTENT_ATTACH_NOT_EXISTS);
            }
            ContentFileVo contentFileVo = attachs.get(index);
            fileUrl = contentFileVo.getUrl();
            fileName = contentFileVo.getName();
        } else {
            fileUrl = contentDO.getSysAttach();
            fileName = contentDO.getSysAttachName();
        }
        if (StringUtils.isBlank(fileUrl)) {
            log.error("Content file not found. id=" + id);
            throw exception(CONTENT_ATTACH_NOT_EXISTS);
        }
        ContentCountDO count = contentDO.getCount();
        int downloads = count.getDownloads() + 1;
        count.setDownloads(downloads);
        contentCountService.updateById(count);
        // fileurl是外部类链接则直接重定向至文件
        if (StringUtils.isNotBlank(fileUrl) && (StringUtils.startsWithAny(fileUrl, HTTP_PROTOCOL, HTTPS_PROTOCOL))) {
            response.sendRedirect(fileUrl);
            return;
        }
        //暂不支持相对路径文件下载
        throw exception(CONTENT_ATTACH_NOT_EXISTS);
    }

    private ContentDO validateContent(Long id, SiteDO site, LoginUser user, Boolean preview) {
        ContentDO contentDO = contentService.getContent(id);
        if (contentDO == null) {
            log.error("Content not found: siteId={}, contentId={}", site.getId(), id);
            throw exception(CONTENT_NOT_EXISTS);
        }
        if (preview != null && preview) {
            if (user == null) {
                throw exception(NO_AUTHORITY);
            }
            return contentDO;
        }
        //非发布状态
        if (!EnumContentStatus.PUBLISHED.getStatus().equals(contentDO.getStatus())) {
            //如果当前用户是管理员或者是用户创建者则可以预览
            if (user != null && user.getUserType().equals(UserTypeEnum.ADMIN.getValue())) {
                return contentDO;
            }
            if (user != null && contentDO.getUserId().equals(user.getId())) {
                return contentDO;
            }
            log.error("Content status error:  contentId={} status={} ", contentDO.getId(), id);
            throw exception(CONTENT_NOT_EXISTS);
        }
        return contentDO;
    }

    private ContentDO validateLivePreviewContent(Long id, SiteDO site, LoginUser user, Boolean preview) {
        ContentDO contentDO = contentService.getContent(id);
        if (contentDO == null) {
            log.error("Content not found: siteId={}, contentId={}", site.getId(), id);
            throw exception(CONTENT_NOT_EXISTS);
        }
        if (preview != null && preview) {
            if (user == null) {
                throw exception(NO_AUTHORITY);
            }
            return contentDO;
        }
        return contentDO;
    }

    private final ContentCountService contentCountService;
    private final ContentService contentService;
    private final SiteService siteService;

    public ContentController(ContentCountService contentCountService, ContentService contentService,
                             SiteService siteService) {
        this.contentCountService = contentCountService;
        this.contentService = contentService;
        this.siteService = siteService;
    }
}
